package com.example.test.util;

import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.hwpf.model.*;
import org.apache.poi.hwpf.usermodel.CharacterRun;
import org.apache.poi.hwpf.usermodel.Paragraph;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * word文字读取以及图片储存
 * @Author 林文峰
 * @Date 2020/6/22 0022 9:26
 */
public class WordUtil {

	private HWPFDocument doc = null;
	
	private XWPFDocument docx = null;

	private Range range = null;

	private static List<Picture> pictsList = null;

	// 用来标记是否存在图片
	boolean hasPic = false;

	/**
	 * 构造器,获取word文档数据
	 *
	 * @param 
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	public WordUtil(MultipartFile file) {
		File f = MultipartFileToFile.multipartFileToFile(file);
		InputStream ins = null;
		try {
			ins = new FileInputStream(f);
			if (f.getName().endsWith("doc")){
				doc = new HWPFDocument(ins);
				range = doc.getRange();
			}else if (f.getName().endsWith("docx")){
				docx = new XWPFDocument(ins);
			}
			CloseUtil.conClose(ins);
			MultipartFileToFile.deleteTempFile(f);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * 默认构造器，为私有函数
	 */
	private WordUtil() {

	}

	/**
	 * 从word文档中获取所有文字，调用对象必须通过构造器初始化。
	 *
	 * @return
	 */
	public String getAllText() {
		StringBuffer ret = new StringBuffer();
		if (doc != null){
			int numP = range.numParagraphs();
			for (int i = 0; i < numP; ++i) {
				//从每一段落中获取文字
				Paragraph p = range.getParagraph(i);
				ret.append(p.text());
			}
		}
		if (docx != null){
			List<XWPFParagraph> paragraphs = docx.getParagraphs();
			paragraphs.forEach(par -> 
					ret.append(par.getText()));
		}
		return ret.toString();
	}

	/**
	 * 从word里面提取图片
	 *
	 * @return
	 */
	private boolean extractPictures() {
		pictsList = new ArrayList();
		// 得到文档的数据流
		byte[] dataStream = doc.getDataStream();
		int numChar = range.numCharacterRuns();
		PicturesTable pTable = new PicturesTable(doc, dataStream, new byte[1024]);
		for (int j = 0; j < numChar; ++j) {
			CharacterRun cRun = range.getCharacterRun(j);
			// 是否有图片
			boolean has = pTable.hasPicture(cRun);
			if (has) {
				Picture picture = pTable.extractPicture(cRun, true);
				// 大于300bites的图片我们才弄下来，消除word中莫名的小图片的影响
//				if (picture.getSize() > 300) {
					pictsList.add(picture);
					hasPic = true;
//				}
			}
		}
		return hasPic;
	}

	/**
	 * word文档里有几张图片，使用这个函数之前，
	 * 必须先使用函数 extractPictures()
	 *
	 * @return
	 */
	public int numPictures() {
		if (!hasPic)
			return 0;
		return pictsList.size();
	}

	/**
	 * 把提取的图片保存到用户指定的位置
	 * @param picNames， 图片要保存的路径,最好完整地写上图片类型
	 * @return
	 */
	private boolean writePictures(String[] picNames, String savePath) {
		int size = pictsList.size();
		if (size == 0)
			return false;
		OutputStream out = null;
		for (int i = 0; i < size; ++i) {
			Picture p = pictsList.get(i);
			try {
				out = new FileOutputStream(savePath + "/" + picNames[i]);
				p.writeImageContent(out);
				CloseUtil.conClose(out);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
	}

	/**
	 * 读取srcFile源word文件docx文字
	 * 读取srcFile源word文件docx中的image图片并且存放在文件夹imageFile中
	 * @Author: 林文峰 
	 * @Date 2020/6/23 0023 13:32
	 */
	private static Map readDocxImage(MultipartFile srcFile, String imageFile) {
//		String path = srcFile;
//		File file = new File(path);
		File file = MultipartFileToFile.multipartFileToFile(srcFile);
		Map<String,String> result = new HashMap<>();
		String text = null;
		try {
			// 用XWPFWordExtractor来获取文字
			FileInputStream fis = new FileInputStream(file);
			XWPFDocument document = new XWPFDocument(fis);
			XWPFWordExtractor xwpfWordExtractor = new XWPFWordExtractor(document);
			text = xwpfWordExtractor.getText();
			//存入map中,去掉/r/n字符
			result.put("wordText",text.replaceAll("(\\\r\\\n|\\\r|\\\n|\\\n\\\r|\\\t)", ""));
//			System.out.println(text);
			// 用XWPFDocument的getAllPictures来获取所有的图片
			List<XWPFPictureData> picList = document.getAllPictures();
			FileOutputStream fos = null;
			for (int i = 0;i < picList.size();i++) {
				XWPFPictureData pic = picList.get(i);
				byte[] bytev = pic.getData();
				// 大于300bites的图片我们才弄下来，消除word中莫名的小图片的影响
//				if (bytev.length > 300) {
					String imagePath = imageFile + "/取个名字"+i+pic.getFileName().substring(pic.getFileName().lastIndexOf("."));
					result.put("imagePath"+i,imagePath.trim());
					fos = new FileOutputStream(imagePath);
					fos.write(bytev);
//				}
				CloseUtil.conClose(fos);
			}
			CloseUtil.conClose(xwpfWordExtractor,document,fis);
			MultipartFileToFile.deleteTempFile(file);
			return result;
		} catch (IOException e) {
			e.printStackTrace();
		}
		MultipartFileToFile.deleteTempFile(file);
		return result;
	}

	/**
	 * doc读取图片和文字
	 * @Author: 林文峰 
	 * @Date 2020/6/22 0022 19:00
	 */
	private static Map readDocImage(MultipartFile file, String savePath) {
		WordUtil extr = new WordUtil(file);
		Map<String,String> result = new HashMap<>();
		String str = extr.getAllText().trim();
		//存入map中,去掉/r/n字符
		result.put("wordText",str.replaceAll("(\\\r\\\n|\\\r|\\\n|\\\n\\\r|\\\t)", ""));
		extr.extractPictures();
		int num = extr.numPictures();
		String names[] = new String[num];
		for (int i = 0; i < num; ++i) {
			String imageType = pictsList.get(i).getMimeType().split("/")[1];
			names[i] = "取个名字" + i + "." + imageType;
			result.put("imagePath"+i,savePath+names[i]);
		}
//		System.out.println(str);
		extr.writePictures(names, savePath);
		return result;
	}

	/**
	 * 图片读取和文字读取，调用上面的方法，返回文件内容
	 * @Author: 林文峰 
	 * @Date 2020/6/22 0022 19:00
	 */
	public static Map readWordImage(MultipartFile file, String savePath) {
		if (null == savePath) {
			savePath = "";
		}
		if (file.getOriginalFilename().endsWith(".doc")) {
			return readDocImage(file, savePath);
		} else if (file.getOriginalFilename().endsWith(".docx")) {
			return readDocxImage(file, savePath);
		} 
		return null;
	}

}
